﻿using AntdUI;
using CodeGenerator.DBInfo;
using CodeGenerator.DBInfo.entity;
using CodeGenerator.Dialog;
using CodeGenerator.Utils;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using static System.Net.Mime.MediaTypeNames;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
using Google.Protobuf.WellKnownTypes;
using System.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;
using System.Text.RegularExpressions;
using MybatisPlusGenerator.Dialog;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.IO.Compression;
using CodeGenerator.DBInfo.metadata;
using static CodeGenerator.Dialog.TemplateConfigDialog;

namespace CodeGenerator
{
    public partial class Main : Form
    {
        public static readonly string Version = "2.0.5";
        public static string VersionStr
        {
            get
            {
                var vStr = Version.ToString();
                if (vStr.Contains("."))
                {

                    return vStr;
                }
                else
                {
                    return $"{vStr}.0";
                }
            }
        }
        private class TbTableRow
        {
            public bool Checked
            {
                get; set;
            }
            public string TableName { get; set; }
            public string DBName { get; set; }
            public string SchemaName { get; set; }
        }
        ConfigUtil ConnConfig
        {
            get
            {
                return new ConfigUtil(ConfigUtil.ConnFile);
            }
        }
        ConfigUtil TplConfig
        {
            get
            {
                return new ConfigUtil(ConfigUtil.TemplateFile);
            }
        }
        ConfigUtil PathConfig
        {
            get
            {
                return new ConfigUtil(ConfigUtil.OutputPathFile);
            }
        }

        JToken AppConfig = null;

        IDBInfoGetter DBGetter;
        ConnectionInfo ConnInfo;
        List<TbTableRow> OriginTbList = new List<TbTableRow>();
        List<TbTableRow> SelectedTableList
        {
            get
            {
                return OriginTbList.Where(x => x.Checked).ToList();
            }
        }
        public Main()
        {
            Program.form = this;
            // 禁用大小可调整性
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            // 禁用最大化按钮
            this.MaximizeBox = false;
            InitializeComponent();
        }
        private void LoadAppConfig()
        {
            var config = new ConfigUtil(ConfigUtil.AppConfigFile);
            var configs = config.GetConfigs();
            if (configs.Count != 0)
            {
                AppConfig = configs[0];
            }
        }
        private void CheckAppUpdate()
        {
            if (AppConfig == null)
            {
                return;
            }
            var url = AppConfig["appUpdateUrl"].ToString();
            url += $"{(url.EndsWith("/") ? "" : "/")}updateLog.json";
            Task.Run(async () =>
            {
                var shouldUpdate = await UpdateUtil.CheckApplicationUpdateVersion(url);
                if (shouldUpdate)
                {
                    Invoke(new Action(() =>
                    {
                        newAppVersionBtn.Visible = true;
                    }));
                }
            });

        }
        private void CheckUpdateNewTemplates()
        {
            if (AppConfig == null)
            {
                return;
            }
            var rootUrl = AppConfig["appUpdateUrl"].ToString();
            rootUrl = $"{rootUrl}{(rootUrl.EndsWith("/") ? "" : "/")}";
            var remoteTemplatesUrl = $"{rootUrl}templates.json";
            Task.Run(async () =>
            {
                //获取远端模板列表
                List<RemoteTemplate> remoteList = await UpdateUtil.GetRemoteTemplates(remoteTemplatesUrl);
                //加载本地远端模板列表
                var localRemotes = TplConfig.GetConfigs().Where(x => x["RemoteId"] != null).ToList();
                //加载本地远端模板id
                var localRemoteIds = localRemotes.Select(x => x["RemoteId"].ToString()).ToList();

                //筛选出已有的模板
                var alreadyRemoteTplList = remoteList.Where(x => localRemoteIds.Contains(x.Id)).ToList();
                var shouldUpdate = false;
                foreach(var local in localRemotes)
                {
                    if (shouldUpdate) break;
                    var localVersion = int.Parse(local["Version"].ToString());
                    foreach (var remote in alreadyRemoteTplList)
                    {
                        if (remote.Id == local["RemoteId"].ToString() && remote.Version > localVersion)
                        {
                            shouldUpdate = true;
                            break;
                        }
                    }
                }
                Invoke(new Action(() => newTplVersionBtn.Visible = shouldUpdate));

                //筛选出新的模板
                var newRemoteTplList = remoteList.Where(x => !localRemoteIds.Contains(x.Id)).ToList();
                //下载新的模板到本地
                foreach (var newTpl in newRemoteTplList)
                {
                    try
                    {
                        var downUrl = $"{rootUrl}{newTpl.RelativePath}";
                        var path = CommonUtil.GenFullPath($"tmp/{newTpl.Id}.zip");
                        UpdateUtil.DownloadFile(downUrl, path);
                        var extractPath = CommonUtil.GenFullPath($"remoteTemplates/{newTpl.Name}");
                        ZipFile.ExtractToDirectory(path, extractPath);
                        //添加到本地模板
                        TplConfig.AddConfig(new TemplateInfo()
                        {
                            RemoteId = newTpl.Id,
                            TplName = newTpl.Name,
                            TplPath = $"remoteTemplates/{newTpl.Name}",
                            Version = newTpl.Version,
                            Type = newTpl.Type
                        });
                    }
                    catch { }
                }
                Invoke(new Action(InitTemplateList));
            });

        }
        private void Main_Load(object sender, EventArgs e)
        {
            this.Text = $"代码生成器 V{VersionStr}";
            //清理临时目录
            var updateDir = CommonUtil.GenFullPath("tmp");
            if (Directory.Exists(updateDir))
            {
                FileUtil.DeleteDirectory(updateDir);
            }
            LoadAppConfig();
            CheckAppUpdate();
            CheckUpdateNewTemplates();
            SetCenterPosition();
            InitConnList();
            InitTemplateList();
            InitOutPutPathList();
            Column[] dbTableHeaders = { new Column("DBName", "数据库", ColumnAlign.Center), };
            dbTable.Columns = dbTableHeaders;
            Column[] schemaTableHeaders = { new Column("SchemaName", "模式", ColumnAlign.Center), };
            schemaTable.Columns = schemaTableHeaders;
            Column[] tbTableHeaders = {
                new ColumnCheck("Checked")
                {
                    Width = "30"
                },
                new Column("TableName", "表名", ColumnAlign.Center),
            };
            tbTable.Columns = tbTableHeaders;
        }
        private void InitConnList()
        {
            var connList = ConnConfig.GetConfigs();
            connSelect.Items.Clear();
            foreach (var conn in connList)
            {
                connSelect.Items.Add(new SelectItem(conn["ConnName"].ToString(), conn));
            }
        }
        private void InitTemplateList()
        {
            var tplList = TplConfig.GetConfigs();
            frontTplSelect.Items.Clear();
            backTplSelect.Items.Clear();
            foreach (var tpl in tplList)
            {
                var item = new SelectItem(tpl["TplName"].ToString(), tpl);
                if (tpl["Type"].ToString() == "front")
                {
                    frontTplSelect.Items.Add(item);
                }
                else
                {
                    backTplSelect.Items.Add(item);
                }
            }
        }
        private void InitOutPutPathList()
        {
            var pathList = PathConfig.GetConfigs();
            frontOutPutSelect.Items.Clear();
            backOutPutSelect.Items.Clear();

            frontOutPutSelect.Items.Add(new SelectItem("默认生成路径", new { Name = "默认生成路径", Path = CommonUtil.GenFullPath("output\\front") }));
            backOutPutSelect.Items.Add(new SelectItem("默认生成路径", new { Name = "默认生成路径", Path = CommonUtil.GenFullPath("output\\back") }));
            frontOutPutSelect.SelectedIndex = 0;
            backOutPutSelect.SelectedIndex = 0;

            foreach (var path in pathList)
            {
                var item = new SelectItem(path["Name"].ToString(), path);
                if (path["Type"].ToString() == "front")
                {
                    frontOutPutSelect.Items.Add(item);
                }
                else
                {
                    backOutPutSelect.Items.Add(item);
                }
            }
        }

        private void SetCenterPosition()
        {
            // 计算窗口在屏幕中的位置
            int screenWidth = Screen.PrimaryScreen.Bounds.Width;
            int screenHeight = Screen.PrimaryScreen.Bounds.Height;
            int windowWidth = this.Width;
            int windowHeight = this.Height;

            int posX = (screenWidth - windowWidth) / 2;
            int posY = (screenHeight - windowHeight) / 2;

            // 设置窗口位置
            this.StartPosition = FormStartPosition.Manual;
            this.Location = new Point(posX, posY);
        }
        private void onConnConfigBtnClicked(object sender, EventArgs e)
        {
            ConnConfigDialog ccg = new ConnConfigDialog();
            ccg.StartPosition = FormStartPosition.CenterParent;
            ccg.ShowDialog();
            InitConnList();
        }

        private async void connSelect_SelectedValueChanged(object sender, dynamic value)
        {
            ConnInfo = GetConnectionInfo(value);
            var dbType = EnumHelper.ParseDbType(ConnInfo.DBType);
            tbSearchInput.Enabled = false;
            tbSearchInput.Text = "";
            switch (dbType)
            {
                case DBType.MySQL:
                    dbTable.Visible = true;
                    schemaTable.Visible = false;
                    dbTable.EmptyText = "加载中...";
                    break;
                case DBType.Oracle:
                    dbTable.Visible = false;
                    schemaTable.Visible = true;
                    schemaTable.EmptyText = "加载中...";
                    break;
                default:
                    dbTable.Visible = true;
                    schemaTable.Visible = true;
                    dbTable.EmptyText = "加载中...";
                    break;
            }
            if (!dbTable.Visible || !schemaTable.Visible)
            {
                //dbTable和schemaTable有一个不可见就将tbTable设置为剩余宽度
                tbTable.Size = new Size(465 + 220, tbTable.Size.Height);
            }
            else
            {
                tbTable.Size = new Size(465, tbTable.Size.Height);
            }
            //触发连接选择后清空列表
            (dbTable.DataSource as AntList<dynamic>)?.Clear();
            dbTable.SelectedIndex = -1;
            (schemaTable.DataSource as AntList<dynamic>)?.Clear();
            schemaTable.SelectedIndex = -1;
            (tbTable.DataSource as AntList<TbTableRow>)?.Clear();
            tbTable.SelectedIndex = -1;
            await Task.Delay(300);
            await Task.Run(() =>
            {
                DBGetter = DBGetterFactory.GetDBGetter(dbType, ConnInfo);
                if (dbType == DBType.Oracle)
                {
                    var schemaList = DBGetter.GetSchemaList(null);
                    schemaList.Sort();
                    InitSchemaTable(null, schemaList);
                }
                else
                {
                    var dblist = DBGetter.GetDbList();
                    dblist.Sort();
                    InitDbTable(dblist);
                }
            });
        }
        private ConnectionInfo GetConnectionInfo(dynamic data)
        {
            return new ConnectionInfo()
            {
                DBType = data["DBType"],
                Host = data["Host"],
                Port = data["Port"],
                UserName = data["UserName"],
                Password = data["Password"],
                ConnName = data["ConnName"],
                InitDb = data["InitDb"],
                Privilege = data["Privilege"],
            };
        }

        private void InitDbTable(List<string> list)
        {
            AntList<dynamic> dbList = new AntList<dynamic>();
            foreach (var item in list)
            {
                dbList.Add(new { DBName = item });
            }
            dbTable.Binding(dbList);
            dbTable.EmptyText = "暂无数据";
        }
        private void InitSchemaTable(string dbName, List<string> list)
        {
            AntList<dynamic> schemaList = new AntList<dynamic>();
            foreach (var item in list)
            {
                schemaList.Add(new { SchemaName = item });
            }
            schemaTable.Binding(schemaList);
            schemaTable.EmptyText = "暂无数据";
        }
        private void InitTbTable(string dbName, string schemaName, List<dynamic> list)
        {
            OriginTbList.Clear();
            Invoke(new Action(() => { tbSearchInput.Enabled = true; }));
            AntList<TbTableRow> tbList = new AntList<TbTableRow>();
            foreach (var item in list)
            {
                OriginTbList.Add(new TbTableRow
                {
                    DBName = dbName,
                    SchemaName = schemaName,
                    TableName = item.Name,
                    Checked = false
                });
            }
            tbList.AddRange(OriginTbList);
            tbTable.Binding(tbList);
            tbTable.EmptyText = "暂无数据";
        }

        private async void dbTable_DoubleClick(object sender, EventArgs e)
        {
            var dbType = EnumHelper.ParseDbType(ConnInfo.DBType);
            var tb = sender as Table;
            var dbName = (dbTable.DataSource as AntList<dynamic>)[tb.SelectedIndex - 1].DBName.ToString();
            switch (dbType)
            {
                case DBType.MySQL:
                    tbTable.EmptyText = "加载中...";
                    (tbTable.DataSource as AntList<TbTableRow>)?.Clear();
                    break;
                case DBType.PostgreSQL:
                    schemaTable.EmptyText = "加载中...";
                    (schemaTable.DataSource as AntList<object>)?.Clear();
                    (tbTable.DataSource as AntList<TbTableRow>)?.Clear();
                    break;
            }
            schemaTable.SelectedIndex = -1;
            tbTable.SelectedIndex = -1;
            await Task.Delay(300);
            await Task.Run(() =>
            {
                switch (dbType)
                {
                    case DBType.MySQL:
                        var tbList = DBGetter.GetTableList(dbName);
                        InitTbTable(dbName, null, tbList);
                        break;
                    case DBType.PostgreSQL:
                        ConnInfo.InitDb = dbName;
                        DBGetter = DBGetterFactory.GetDBGetter(DBType.PostgreSQL, ConnInfo);
                        var schemaList = DBGetter.GetSchemaList(dbName);
                        InitSchemaTable(dbName, schemaList);
                        break;
                }
            });
        }
        private async void schemaTable_DoubleClick(object sender, EventArgs e)
        {
            var dbType = EnumHelper.ParseDbType(ConnInfo.DBType);
            var tb = sender as Table;
            tbTable.EmptyText = "加载中...";
            (tbTable.DataSource as AntList<TbTableRow>)?.Clear();
            tbTable.SelectedIndex = -1;
            await Task.Delay(300);
            await Task.Run(() =>
            {
                var tbList = new List<dynamic>();
                var schemaName = (schemaTable.DataSource as AntList<dynamic>)[schemaTable.SelectedIndex - 1].SchemaName.ToString();
                switch (dbType)
                {
                    case DBType.Oracle:
                        tbList = DBGetter.GetTableList(schemaName);
                        InitTbTable(null, schemaName, tbList);
                        break;
                    case DBType.PostgreSQL:
                        var dbName = (dbTable.DataSource as AntList<dynamic>)[dbTable.SelectedIndex - 1].DBName.ToString();
                        tbList = DBGetter.GetTableList(schemaName);
                        InitTbTable(dbName, schemaName, tbList);
                        break;
                }
            });
        }
        private void tbTable_DoubleClick(object sender, EventArgs e)
        {
            var tb = sender as Table;
            int index = tb.SelectedIndex - 1;
            var list = (tbTable.DataSource as AntList<TbTableRow>);
            if (list == null || index < 0 || index >= list.Count) return;
            var data = list[index];
            data.Checked = !data.Checked;
            tb.Binding(list);
        }

        private void onTemplateConfigBtnClicked(object sender, EventArgs e)
        {
            TemplateConfigDialog tcg = new TemplateConfigDialog();
            tcg.StartPosition = FormStartPosition.CenterParent;
            tcg.ShowDialog();
            InitTemplateList();
            CheckUpdateNewTemplates();
        }

        private void openConfigDirBtn_Click(object sender, EventArgs e)
        {
            var dir = CommonUtil.GenFullPath("configs");
            Directory.CreateDirectory(dir);
            Process.Start(dir);
        }

        private void frontOpenGenPathBtn_Click(object sender, EventArgs e)
        {
            var path = (frontOutPutSelect.SelectedValue as dynamic).Path.ToString();
            var dir = CommonUtil.GenFullPath(path);
            Directory.CreateDirectory(dir);
            Process.Start(dir);
        }

        private void backOpenGenPathBtn_Click(object sender, EventArgs e)
        {
            var path = (backOutPutSelect.SelectedValue as dynamic).Path.ToString();
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            Process.Start(path);
        }

        private void outputPathCfgBtn_Click(object sender, EventArgs e)
        {
            OutputConfigDialog dialog = new OutputConfigDialog();
            dialog.StartPosition = FormStartPosition.CenterParent;
            dialog.ShowDialog();
            InitOutPutPathList();
        }

        private void tbSearchInput_TextChanged(object sender, EventArgs e)
        {
            var input = sender as Input;
            var searchText = input.Text.ToLower();
            var list = tbTable.DataSource as AntList<TbTableRow>;
            if (list == null) return;
            list.Clear();
            var tmpList = new List<TbTableRow>();
            foreach (var tb in OriginTbList)
            {
                if (tb.TableName.ToLower().Contains(searchText))
                {
                    tmpList.Add(tb);
                }
            }
            if (tmpList.Count > 0)
            {
                list.AddRange(tmpList);
            }
        }
        private void GenTemplateControl(dynamic value, FlowPanel container)
        {
            var templateRootPath = CommonUtil.GenFullPath(value["TplPath"].ToString());
            var templateJsonPath = templateRootPath + "\\template.json";
            var text = File.ReadAllText(templateJsonPath);
            var json = JsonConvert.DeserializeObject<JObject>(text);
            //var templateName = value["TplName"].ToString();
            var templates = json["templates"] as IEnumerable<dynamic>;
            container.SuspendLayout();
            //移除旧的控件
            for (var i = container.Controls.Count - 1; i >= 0; i--)
            {
                var item = container.Controls[i];
                if ((item).Name != "basePkgInput")
                {
                    container.Controls.Remove(item as Control);
                }
            }
            //渲染新的控件
            foreach (var template in templates)
            {
                var item = template as JToken;
                var name = item["name"].ToString();
                var path = $"{templateRootPath},{item["outputDir"]},{item["templateName"]},{item["outputName"]}";
                var checkbox = new AntdUI.Checkbox();
                checkbox.Size = new Size(width: 125, height: 33);
                checkbox.Name = name;
                checkbox.Text = name;
                checkbox.Checked = true;
                checkbox.Tag = path;
                checkbox.Font = new Font("微软雅黑", 10F);
                container.Controls.Add(checkbox);
                //移动到末尾
                container.Controls.SetChildIndex(checkbox, 0);
            }
            //渲染额外控件
            var extra = json["extra"] as IEnumerable<dynamic>;
            foreach (var item in extra)
            {
                var name = item["name"].ToString();
                var type = item["type"].ToString();
                var defaultVal = item["default"].ToString();
                Control customControl = null;
                switch (type)
                {
                    case "checkbox":
                        Checkbox checkbox = new Checkbox();
                        checkbox.Checked = bool.Parse(defaultVal);
                        checkbox.Text = item["text"].ToString();
                        customControl = checkbox;
                        break;
                    case "input":
                        Input input = new Input();
                        input.PrefixText = item["prefix"].ToString();
                        if (input.PrefixText.IsNullOrEmpty())
                        {
                            throw new Exception($"{name} 的 PrefixText 字段不能为空");
                        }
                        input.PlaceholderText = item["placeholder"].ToString();
                        input.Text = defaultVal;
                        customControl = input;
                        string rule = item["rule"].ToString();
                        var errMsg = item["errMsg"].ToString();
                        string required = item["required"].ToString();
                        var req = required.IsNotNullAndNotEmpty() ? bool.Parse(required) : false;
                        input.Validating += (object sender1, CancelEventArgs e) =>
                        {
                            if (required.IsNullOrEmpty())
                            {
                                return;
                            }
                            if (req && input.Text.IsNullOrEmpty())
                            {
                                throw new Exception($"{input.PrefixText} 不能为空");
                            }
                            if (rule.IsNotNullAndNotEmpty() && !Regex.IsMatch(input.Text, rule))
                            {
                                throw new Exception(errMsg);
                            }
                        };
                        customControl = input;
                        break;
                    case "select":
                        Select select = new Select();
                        select.PrefixText = item["prefix"].ToString();
                        if (select.PrefixText.IsNullOrEmpty())
                        {
                            throw new Exception($"{name} 的 PrefixText 字段不能为空");
                        }
                        select.Text = defaultVal;
                        select.PlaceholderText = item["placeholder"].ToString();
                        select.Items.AddRange((item["values"] as JArray).ToArray());
                        required = item["required"].ToString();
                        req = required.IsNotNullAndNotEmpty() ? bool.Parse(required) : false;
                        select.AllowClear = true;
                        select.Validating += (object sender1, CancelEventArgs e) =>
                        {
                            if (required.IsNullOrEmpty())
                            {
                                return;
                            }
                            if (req && select.Text.IsNullOrEmpty())
                            {
                                throw new Exception($"{select.PrefixText} 不能为空");
                            }
                        };
                        customControl = select;
                        break;
                    default:
                        throw new Exception($"不支持的控件 {type}");
                }
                customControl.Name = $"extra_{name}";
                customControl.Font = new Font("微软雅黑", 10F);
                customControl.Size = new Size(width: 125, height: 33);
                if (item["width"] != null)
                {
                    var width = int.Parse(item["width"].ToString());
                    customControl.Width = width;
                }
                container.Controls.Add(customControl);
                container.Controls.SetChildIndex(customControl, 0);
            }
            container.ResumeLayout(true);
        }
        /// <summary>
        /// 前端生成模板选择事件
        /// </summary>
        /// <param name="sender">调用方</param>
        /// <param name="value">选择的值</param>
        private void frontTplSelect_SelectedValueChanged(object sender, object value)
        {
            GenTemplateControl(value as dynamic, frontGenPanel);
        }
        /// <summary>
        /// 后台生成模板选择事件
        /// </summary>
        /// <param name="sender">调用方</param>
        /// <param name="value">选择的值</param>
        private void backTplSelect_SelectedValueChanged(object sender, object value)
        {
            GenTemplateControl(value as dynamic, backGenPanel);
        }
        /// <summary>
        /// 生成后台代码
        /// </summary>
        /// <param name="sender">调用方</param>
        /// <param name="value">选择的值</param>
        private void genBackBtn_Click(object sender, EventArgs e)
        {
            if (backTplSelect.Text.IsNullOrEmpty())
            {
                throw new Exception("请先选择生成模板");
            }
            if (!basePkgInput.Text.IsJavaPackageName())
            {
                throw new Exception("请输入合法的Java包名");
            }
            CollectGenInfo(backGenPanel, out List<string> pathList, out List<TbTableRow> tableList, out Dictionary<string, dynamic> extraVars);
            GenerateCode("back", pathList, tableList, extraVars);
        }

        private void genFrontBtn_Click(object sender, EventArgs e)
        {
            CollectGenInfo(frontGenPanel, out List<string> pathList, out List<TbTableRow> tableList, out Dictionary<string, dynamic> extraVars);
            GenerateCode("front", pathList, tableList, extraVars);
        }
        /// <summary>
        /// 收集生成所需信息
        /// </summary>
        /// <param name="templatePathList">模板路径列表</param>
        /// <param name="tableList">表列表</param>
        /// <param name="extraVars">额外变量</param>
        private void CollectGenInfo(FlowPanel container, out List<string> templatePathList, out List<TbTableRow> tableList, out Dictionary<string, dynamic> extraVars)
        {
            var selectedList = SelectedTableList;
            if (selectedList.Count == 0)
            {
                throw new Exception("请先选择表");
            }
            //仅验证可见控件
            ValidateChildren(ValidationConstraints.Visible);
            List<string> pathList = new List<string>();
            var extra = new Dictionary<string, dynamic>();
            foreach (var item in container.Controls)
            {
                var control = item as Control;
                if (control.Name == "basePkgInput")
                {
                    continue;
                }
                if (control.Name.StartsWith("extra_"))
                {
                    var name = control.Name.Replace("extra_", "");
                    if (control is Checkbox)
                    {
                        extra[name] = (control as Checkbox).Checked.ToString();
                    }
                    else
                    {
                        extra[name] = control.Text;
                    }
                    continue;
                }
                var checkbox = item as AntdUI.Checkbox;
                //未选择，跳过
                if (!checkbox.Checked)
                {
                    continue;
                }
                //将模板路径添加到list中
                var tags = (checkbox.Tag as string).Split(',');
                if (!File.Exists($"{tags[0]}\\{tags[2]}"))
                {
                    throw new Exception($"{checkbox.Name} 的模板文件不存在");
                }
                pathList.Add(checkbox.Tag as string);
            }
            if (pathList.Count == 0)
            {
                throw new Exception("请选择要生成的内容");
            }
            templatePathList = pathList;
            tableList = selectedList;
            extraVars = extra;
        }
        private async void GenerateCode(string genType, List<string> templatePathList, List<TbTableRow> tableList, Dictionary<string, dynamic> extraVars)
        {
            Select tplSelect;
            Select outputSelect;
            var module = moduleName.Text;
            AntdUI.Button genBtn;
            switch (genType)
            {
                case "front":
                    tplSelect = frontTplSelect;
                    outputSelect = frontOutPutSelect;
                    genBtn = genFrontBtn;
                    break;
                case "back":
                    tplSelect = backTplSelect;
                    outputSelect = backOutPutSelect;
                    genBtn = genBackBtn;
                    break;
                default:
                    throw new Exception("不支持的模板类型");
            }

            //模板根路径
            var templateRootPath = CommonUtil.GenFullPath((tplSelect.SelectedValue as dynamic)["TplPath"].ToString());
            //生成路径
            var outputPath = (outputSelect.SelectedValue as dynamic).Path.ToString();
            //开始生成
            genBtn.Loading = true;
            var genIndex = 1;
            var genTotal = tableList.Count;
            genBtn.Text = $"{genIndex} / {genTotal}";
            var hasError = false;
            try
            {
                //若是默认生成目录则清理生成目录
                if (outputSelect.Text.Contains("默认"))
                {
                    FileUtil.DeleteDirectory(outputPath);
                }
                foreach (var table in tableList)
                {
                    //开始生成
                    var dbName = table.DBName;
                    var schemaName = table.SchemaName;
                    var tableName = table.TableName;
                    var tableInfo = DBGetter.GetTableInfo(dbName, schemaName, tableName);
                    var basePkg = basePkgInput.Text;
                    if (tableInfo.PrimaryKeyCount != 1)
                    {
                        var tip = "";
                        if (tableInfo.PrimaryKeyCount == 0)
                            tip = $"{tableName} 表无主键，是否继续生成该表？";
                        if (tableInfo.PrimaryKeyCount > 1)
                            tip = $"{tableName} 表含有联合主键，模板可能不会添加主键标记，是否继续生成该表？";
                        var dlgRes = AntdUI.Modal.open(new AntdUI.Modal.Config(this, "提示", tip, AntdUI.TType.Success)
                        {
                            CancelText = "取消",
                            OkText = "确定"
                        });
                        if (dlgRes == DialogResult.Cancel)
                        {
                            //虽然跳过该次生成，但是次数还得++
                            genBtn.Text = $"{++genIndex} / {genTotal}";
                            continue;
                        }
                        await Task.Delay(100);
                    }
                    //删除表名指定前缀
                    var prefix = clearTbPrefixInput.Text;
                    if (prefix.IsNotNullAndNotEmpty())
                    {
                        //正则替换
                        tableInfo.TrimPrefixName = Regex.Replace(tableInfo.Name, prefix, "", RegexOptions.IgnoreCase);
                    }
                    //循环生成模板项
                    foreach (var templatePathInfo in templatePathList)
                    {
                        var pathInfos = templatePathInfo.Split(',');
                        if (genTabs.SelectedIndex == 0)
                        {
                            //前端
                            TemplateGenerator.GenerateFrontCode(DBGetter, module, tableInfo, templateRootPath, pathInfos, outputPath, extraVars);
                        }
                        else
                        {
                            //后端
                            TemplateGenerator.GenerateBackCode(DBGetter, module, tableInfo, basePkg, templateRootPath, pathInfos, outputPath, extraVars);
                        }
                    }
                    genBtn.Text = $"{++genIndex} / {genTotal}";
                }
            }
            catch (Exception ex)
            {
                AntdUI.Modal.open(new AntdUI.Modal.Config(this, "生成失败", ex.Message, AntdUI.TType.Error)
                {
                    CancelText = null,
                    OkText = "确定"
                });
                hasError = true;
            }
            finally
            {
                genBtn.Loading = false;
                genBtn.Text = "开始生成";
            }
            if (hasError) return;
            var res = AntdUI.Modal.open(new AntdUI.Modal.Config(this, "生成成功", "是否打开生成目录？", AntdUI.TType.Success)
            {
                CancelText = "取消",
                OkText = "确定"
            });

            if (res == DialogResult.OK)
            {
                Process.Start(outputPath);
            }
        }
        private void GenTableColumns(string style)
        {
            var selected = SelectedTableList;
            if (selected.Count == 0)
            {
                throw new Exception("请先选择表");
            }
            if (selected.Count > 1)
            {
                throw new Exception("只能选择一张表");
            }
            var table = selected[0];
            var tableInfo = DBGetter.GetTableInfo(table.DBName, table.SchemaName, table.TableName);
            TableColumnDialog dialog = new TableColumnDialog(style, tableInfo);
            dialog.StartPosition = FormStartPosition.CenterParent;
            dialog.ShowDialog();
        }
        private void sgtbStyleBtn_Click(object sender, EventArgs e)
        {
            GenTableColumns("SGTable");
        }


        private void antdTbStyleBtn_Click(object sender, EventArgs e)
        {
            GenTableColumns("Antd");
        }

        private void updateCfgBtn_Click(object sender, EventArgs e)
        {
            UpdateConfigDialog tcg = new UpdateConfigDialog();
            tcg.StartPosition = FormStartPosition.CenterParent;
            tcg.ShowDialog();
            LoadAppConfig();
        }

        private async void newVersionBtn_Click(object sender, EventArgs e)
        {
            newAppVersionBtn.Loading = true;
            var url = AppConfig["appUpdateUrl"].ToString();
            url += $"{(url.EndsWith("/") ? "" : "/")}updateLog.json";
            var oldText = newAppVersionBtn.Text;
            newAppVersionBtn.Text = "加载中";
            await UpdateUtil.CheckApplicationUpdateVersion(url, true, new Action(() =>
            {
                Invoke(new Action(() =>
                {
                    newAppVersionBtn.Loading = false;
                    newAppVersionBtn.Text = oldText;
                }));
            }));
        }

        private void newTplVersionBtn_Click(object sender, EventArgs e)
        {
            onTemplateConfigBtnClicked(null, null);
        }
    }
}
